"""
闲鱼WebSocket客户端模块 (原 easy.py)
提供闲鱼聊天服务的WebSocket连接和消息处理功能
"""

import base64
import json
import asyncio
import time
import os
import urllib.parse
from dotenv import load_dotenv

from loguru import logger
import websockets

from .xianyu_api import XianyuAPI
from .movie_api import MovieAPI
from utils.xianyu_utils import generate_mid, generate_uuid, trans_cookies, generate_device_id, decrypt

# 加载环境变量
load_dotenv()

# 全局配置
_ENV_PATH = os.path.join(os.getcwd(), '.env')
_ENV_MTIME = None
_PRICE_TYPE = '固定上浮'
_PRICE_VALUE = 0.0

# 常量定义
CACHE_EXPIRE_TIME = 300  # 缓存有效期（秒）
HEARTBEAT_INTERVAL = 15  # 心跳间隔（秒）
MESSAGE_DELAY = 1  # 消息发送延迟（秒）

# 消息类型
MSG_TYPE_TEXT = "文字"
MSG_TYPE_IMAGE = "图片"

# 识别失败的默认图片
DEFAULT_ERROR_IMAGE = 'https://img.alicdn.com/imgextra/i4/2349894620/O1CN01BeF5nQ1k00vTcC0dO_!!2349894620-2-xy_chat.png'

# GUI回调函数
gui_log_callback = None
gui_show_antispam_callback = None


def _refresh_price_cfg():
    """刷新价格配置"""
    global _ENV_MTIME, _PRICE_TYPE, _PRICE_VALUE
    try:
        m = os.path.getmtime(_ENV_PATH)
    except Exception:
        m = None
    if m is None or m == _ENV_MTIME:
        return
    _ENV_MTIME = m
    load_dotenv(override=True)
    t = (os.getenv('PRICE_MARKUP_TYPE', '固定上浮') or '固定上浮').strip()
    v_str = (os.getenv('PRICE_MARKUP_VALUE', '0') or '0').strip()
    try:
        v = float(v_str)
    except Exception:
        v = 0.0
    _PRICE_TYPE = t
    _PRICE_VALUE = v


def _get_price_cfg():
    """获取价格配置"""
    _refresh_price_cfg()
    return _PRICE_TYPE, _PRICE_VALUE


def set_gui_log_callback(callback):
    """设置GUI日志回调函数"""
    global gui_log_callback
    gui_log_callback = callback


def add_gui_log(message):
    """添加GUI日志信息"""
    global gui_log_callback
    if gui_log_callback:
        try:
            gui_log_callback(message)
        except Exception as e:
            logger.error(f"GUI日志添加失败: {e}")


def set_gui_show_antispam_callback(callback):
    """设置GUI反爬虫提示回调函数"""
    global gui_show_antispam_callback
    gui_show_antispam_callback = callback


def show_antispam_prompt():
    """显示反爬虫提示"""
    global gui_show_antispam_callback
    if gui_show_antispam_callback:
        try:
            gui_show_antispam_callback()
        except Exception as e:
            logger.error(f"GUI反爬虫提示失败: {e}")
    else:
        logger.warning("GUI回调函数未设置，无法显示反爬虫提示")


class XianyuClient:
    """闲鱼WebSocket客户端类"""
    
    def __init__(self, cookies_str):
        """
        初始化客户端
        
        Args:
            cookies_str: 闲鱼Cookie字符串
        """
        self.xianyu = XianyuAPI()
        self.movie_api = MovieAPI()
        self.base_url = 'wss://wss-goofish.dingtalk.com/'
        self.cookies_str = cookies_str
        self.cookies = trans_cookies(cookies_str)
        self.myid = self.cookies['unb']  # 用户ID
        self.device_id = generate_device_id(self.myid)
        self.ws = None
        self._users_first_text_replied = set()

    async def create_chat(self, ws, toid, item_id='891198795482'):
        """创建聊天会话"""
        msg = {
            "lwp": "/r/SingleChatConversation/create",
            "headers": {"mid": generate_mid()},
            "body": [{
                "pairFirst": f"{toid}@goofish",
                "pairSecond": f"{self.myid}@goofish",
                "bizType": "1",
                "extension": {"itemId": item_id},
                "ctx": {"appVersion": "1.0", "platform": "web"}
            }]
        }
        await ws.send(json.dumps(msg))

    async def _send_message_base(self, ws, cid, toid, content_base64):
        """发送消息的基础方法"""
        msg = {
            "lwp": "/r/MessageSend/sendByReceiverScope",
            "headers": {"mid": generate_mid()},
            "body": [
                {
                    "uuid": generate_uuid(),
                    "cid": f"{cid}@goofish",
                    "conversationType": 1,
                    "content": {
                        "contentType": 101,
                        "custom": {"type": 1, "data": content_base64}
                    },
                    "redPointPolicy": 0,
                    "extension": {"extJson": "{}"},
                    "ctx": {"appVersion": "1.0", "platform": "web"},
                    "mtags": {},
                    "msgReadStatusSetting": 1
                },
                {
                    "actualReceivers": [f"{toid}@goofish", f"{self.myid}@goofish"]
                }
            ]
        }
        await ws.send(json.dumps(msg))

    async def send_msg(self, ws, cid, toid, text):
        """发送文字消息"""
        content = {"contentType": 1, "text": {"text": text}}
        content_base64 = base64.b64encode(json.dumps(content).encode('utf-8')).decode('utf-8')
        await self._send_message_base(ws, cid, toid, content_base64)

    async def send_image_msg(self, ws, cid, toid, image_url):
        """发送图片消息"""
        content = {
            "contentType": 2,
            "image": {"pics": [{"url": image_url, "width": 200, "height": 200}]}
        }
        content_base64 = base64.b64encode(json.dumps(content).encode('utf-8')).decode('utf-8')
        await self._send_message_base(ws, cid, toid, content_base64)

    def _extract_token(self, token_response):
        """提取访问令牌"""
        # 检查反爬虫验证
        if 'ret' in token_response and 'FAIL_SYS_USER_VALIDATE' in token_response['ret']:
            logger.error("检测到反爬虫验证，需要人工处理")
            logger.error(f"错误信息: {token_response['ret'][1]}")
            if 'data' in token_response and 'url' in token_response['data']:
                logger.error(f"验证码URL: {token_response['data']['url']}")

            show_antispam_prompt()
            return None

        # 提取token
        if 'data' in token_response and 'accessToken' in token_response['data']:
            return token_response['data']['accessToken']
        return token_response.get('accessToken')

    async def init_connection(self, ws):
        """初始化WebSocket连接"""
        try:
            add_gui_log("正在获取访问令牌...")
            token_response = self.xianyu.get_token(self.cookies, self.device_id)
            add_gui_log("Token刷新成功")

            token = self._extract_token(token_response)
            if not token:
                error_msg = "无法获取accessToken，程序退出"
                add_gui_log(f"错误: {error_msg}")
                logger.error(error_msg)
                return

            add_gui_log(f"成功获取token: {token[:20]}...")
            logger.debug(f"成功获取token: {token[:20]}...")

        except Exception as e:
            error_msg = f"获取token失败: {e}"
            add_gui_log(f"错误: {error_msg}")
            logger.error(error_msg)
            return

        # 发送注册消息
        reg_msg = {
            "lwp": "/reg",
            "headers": {
                "cache-header": "app-key token ua wv",
                "app-key": "444e9908a51d1cb236a27862abc769c9",
                "token": token,
                "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 DingTalk(2.1.5) OS(Windows/10) Browser(Chrome/133.0.0.0) DingWeb/2.1.5 IMPaaS DingWeb/2.1.5",
                "dt": "j",
                "wv": "im:3,au:3,sy:6",
                "sync": "0,0;0;0;",
                "did": self.device_id,
                "mid": generate_mid()
            }
        }
        await ws.send(json.dumps(reg_msg))

        # 发送同步状态确认
        current_time = int(time.time() * 1000)
        sync_msg = {
            "lwp": "/r/SyncStatus/ackDiff",
            "headers": {"mid": generate_mid()},
            "body": [{
                "pipeline": "sync",
                "tooLong2Tag": "PNM,1",
                "channel": "sync",
                "topic": "sync",
                "highPts": 0,
                "pts": current_time * 1000,
                "seq": 0,
                "timestamp": current_time
            }]
        }
        await ws.send(json.dumps(sync_msg))
        logger.debug("WebSocket连接初始化完成")

    async def heart_beat(self, ws):
        """心跳保活机制"""
        while True:
            try:
                await ws.send(json.dumps({"lwp": "/!", "headers": {"mid": generate_mid()}}))
                await asyncio.sleep(HEARTBEAT_INTERVAL)
            except Exception as e:
                logger.error(f"心跳发送失败: {e}")
                break

    def _extract_item_id(self, reminder_url):
        """从提醒URL中提取商品ID"""
        try:
            url_parts = reminder_url.split("?")
            if len(url_parts) > 1:
                params = urllib.parse.parse_qs(url_parts[1])
                return params.get("itemId", [""])[0]
        except:
            pass
        return ""

    def _parse_content_json(self, content_json, default_message):
        """解析消息内容JSON"""
        # 图片消息
        if content_json.get("contentType") == 2 and "image" in content_json:
            pics = content_json["image"].get("pics", [])
            if pics:
                image_url = pics[0].get("url", "")
                if image_url:
                    return {"type": MSG_TYPE_IMAGE, "data": image_url}

        # 文字消息
        elif content_json.get("contentType") == 1 and "text" in content_json:
            text = content_json["text"].get("text", default_message)
            return {"type": MSG_TYPE_TEXT, "data": text}

        return {"type": MSG_TYPE_TEXT, "data": default_message}

    def _parse_message_content(self, message_data):
        """解析消息内容"""
        if "1" not in message_data or "10" not in message_data["1"]:
            return None

        msg_info = message_data["1"]["10"]
        user_name = msg_info.get("reminderTitle", "")
        user_id = msg_info.get("senderUserId", "")
        default_message = msg_info.get("reminderContent", "")

        if not user_name or not default_message:
            return None

        # 提取商品ID
        item_id = self._extract_item_id(msg_info.get("reminderUrl", ""))

        # 解析消息内容
        message_result = {"type": MSG_TYPE_TEXT, "data": default_message}
        full_data = message_data["1"]

        if "6" in full_data and "3" in full_data["6"] and "5" in full_data["6"]["3"]:
            try:
                content_json = json.loads(full_data["6"]["3"]["5"])
                message_result = self._parse_content_json(content_json, default_message)
            except json.JSONDecodeError:
                pass

        return {
            "user_name": user_name,
            "user_id": user_id,
            "message": message_result,
            "item_id": item_id
        }

    def _apply_price_markup(self, base_cents):
        """应用价格上浮规则"""
        cfg_type, cfg_value = _get_price_cfg()
        if cfg_type == '固定上浮':
            return int(base_cents + int(round(cfg_value * 100)))
        if cfg_type == '比例上浮':
            inc = int(round(base_cents * (cfg_value / 100.0)))
            return int(base_cents + inc)
        return int(base_cents)

    def _format_movie_quote(self, movie_data):
        """格式化电影报价信息"""
        adjusted_single_cents = self._apply_price_markup(int(movie_data.get("api_price_single", 0)))
        seat_count = int(movie_data.get("seat_num", 1) or 1)
        adjusted_total_cents = adjusted_single_cents * seat_count
        return (
            f'------------购票信息------------\n'
            f'影院：{movie_data.get("city_name", "未知城市")}|{movie_data.get("cinema_name", "未知影院")}\n'
            f'影片：{movie_data.get("film_name", "未知电影")}\n'
            f'影厅：{movie_data.get("hall_name", "未知影厅")}\n'
            f'座位：{movie_data.get("seat", "未知座位")}\n'
            f'场次：{movie_data.get("show_time", "未知场次")}\n'
            f'-------核对信息，不对勿拍-------\n\n'
            f'原价：{movie_data.get("market_price_single", 0)/100:.2f}元/张\n'
            f'特价：{adjusted_single_cents/100:.2f}元/张\n'
            f'{seat_count}张合计：{adjusted_total_cents/100:.2f}元\n\n'
            f'因票价浮动【此报价5分钟内有效】\n'
            f'觉得合适的话早点下单！\n'
            f'注意：图片不能连发，否则以最后一张图片识别结果为准'
        )

    def _format_order_detail(self, movie_data):
        """格式化订单详情信息"""
        adjusted_single_cents = self._apply_price_markup(int(movie_data.get("api_price_single", 0)))
        seat_count = int(movie_data.get("seat_num", 1) or 1)
        adjusted_total_cents = adjusted_single_cents * seat_count
        return (
            f'订单确认 \n'
            f'影片：{movie_data.get("film_name", "未知电影")}\n'
            f'影院：{movie_data.get("city_name", "未知城市")}|{movie_data.get("cinema_name", "未知影院")}\n'
            f'影厅：{movie_data.get("hall_name", "未知影厅")}\n'
            f'场次：{movie_data.get("show_time", "未知场次")}\n'
            f'座位：{movie_data.get("seat", "未知座位")}\n'
            f'数量：{movie_data.get("seat_num", 1)}张\n'
            f'总价：{adjusted_total_cents/100:.2f}元\n\n'
            f'请尽快付款以便出票~\n'
            f'《购票须知》\n'
            f'1. 一般5-40分钟左右出票成功，夜间延迟。\n'
            f'2. 付款后系统自动出票，人工无法拦截！！\n'
            f'3. 订票后【不能退款、不能改签】,考虑清楚后再下单！\n'
            f'4. 介意勿下单，付款即同意！'
        )

    def _get_purchase_notice(self):
        return (
            "购票须知\n"
            "1.特别提示：本店采用机器人自动识别截图出票，若文字描述与截图信息不一致，以截图为准！购票信息有误请勿下单，相关后果由买家自行承担。\n"
            "2.出票过程中，若已选座位出现被占、被锁等情况，系统将自动调配至邻近座位；调座无需另行通知，人工无法干预；多张连坐票下单后，调座将优先保障连座权益，不接受此规则请勿下单。\n"
            "3.出票时效预计 15-60 分钟，付款后不可中断订单、退款或更换场次/座位，请谨慎付款；出票成功后，不支持改签及退票。\n"
            "4.受不可抗力等因素影响，出票成功率非 100%，若出票失败将全额退款；本店不提供任何形式的补偿或赔偿，请提前数小时下单，预留充足出票时间，避免耽误行程。\n"
            "5.若因取票机故障无法取票，可直接前往前台办理；请勿擅自另行购票，由此产生的损失由买家自行承担。\n"
            "请仔细阅读以上须知，避免产生不必要的纠纷；介意以上规则者请勿下单！"
        )

    def _log_paid_order(self, movie_data):
        """记录已付款订单日志"""
        adjusted_single_cents = self._apply_price_markup(int(movie_data.get('api_price_single', 0)))
        seat_count = int(movie_data.get('seat_num', 1) or 1)
        adjusted_total_cents = adjusted_single_cents * seat_count
        logger.info(
            f"   买家已付款 - 订单详情:\n"
            f"   影片：{movie_data.get('film_name', '未知电影')}\n"
            f"   影院：{movie_data.get('city_name', '未知城市')}|{movie_data.get('cinema_name', '未知影院')}\n"
            f"   影厅：{movie_data.get('hall_name', '未知影厅')}\n"
            f"   场次：{movie_data.get('show_time', '未知场次')}\n"
            f"   座位：{movie_data.get('seat', '未知座位')}\n"
            f"   数量：{movie_data.get('seat_num', 1)}张\n"
            f"   总价：{adjusted_total_cents/100:.2f}元"
        )

    async def _handle_image_message(self, websocket, parsed_msg, user_id):
        """处理图片消息"""
        log_message = f"[消息类型:图片][身份:对方][用户:{parsed_msg['user_id']}]-[商品:{parsed_msg['item_id']}]-{parsed_msg['user_name']}: {parsed_msg['message']}"
        logger.info(log_message)
        add_gui_log(log_message)

        image_url = parsed_msg['message']['data']
        add_gui_log("正在识别电影座位图片...")
        movie_info = self.movie_api.get_movies_info(image_url)

        # API调用失败
        if not movie_info or movie_info.get('code') != 200:
            error_msg = movie_info.get('msg', '未知错误') if movie_info else 'API调用失败'
            error_log = f"图片识别失败: {error_msg}"
            logger.error(error_log)
            add_gui_log(error_log)
            return {
                'type': 'image_error',
                'text_reply': '亲亲~ 没有找到当前场次哦!',
                'image_url': DEFAULT_ERROR_IMAGE
            }

        # API调用成功
        movie_data = movie_info.get('data', {})
        success_log = f"[API座位识别成功] - 电影: {movie_data}"
        logger.debug(success_log)
        add_gui_log(success_log)

        add_gui_log("正在创建订单...")
        seat_count = int(movie_data.get('seat_num', 1) or 1)
        api_price_single_cents = int(movie_data.get('api_price_single', 0) or 0)
        movie_data_for_order = dict(movie_data)
        movie_data_for_order['api_price'] = api_price_single_cents * seat_count
        order_result = self.movie_api.movie_goofish_order_create(
            buyer_id=parsed_msg['user_id'],
            seller_id=self.myid,
            goods_id=parsed_msg['item_id'],
            buyer_nickname=parsed_msg['user_name'],
            movie_data=movie_data_for_order,
            img_url=image_url,
        )
        if not order_result or order_result.get('code') != 200:
            msg = order_result.get('msg', '下单失败') if order_result else '下单失败'
            error_log = f"订单创建失败: {msg}"
            logger.error(error_log)
            add_gui_log(error_log)
            return {'type': 'text', 'reply': '亲亲~ 下单失败，请稍后重试~'}

        success_log = f"订单创建成功 - 买家: {parsed_msg['user_name']}, 电影: {movie_data.get('film_name', '未知')}"
        add_gui_log(success_log)
        return {'type': 'text', 'reply': self._format_movie_quote(movie_data)}

    async def _handle_pending_payment_message(self, parsed_msg):
        """处理待付款消息"""
        log_message = f"收到待付款消息 - 用户: {parsed_msg['user_name']}"
        logger.debug(log_message)
        add_gui_log(log_message)

        info = self.movie_api.movie_goofish_order_info(
            buyer_id=parsed_msg['user_id'],
            seller_id=self.myid,
            goods_id=parsed_msg['item_id'],
        )
        if info and info.get('code') == 200 and isinstance(info.get('data'), dict):
            add_gui_log("订单信息查询成功")
            # 更新订单状态为待付款 (state=1)
            order_no = info['data'].get('order_no')
            if order_no:
                try:
                    update_result = self.movie_api.movie_goofish_order_update(order_no, 1)
                    add_gui_log(f"订单状态已更新为待付款: {update_result}")
                except Exception as e:
                    logger.error(f"更新订单状态失败: {e}")
                    add_gui_log(f"更新订单状态失败: {e}")
            return self._format_order_detail(info['data'])
        else:
            add_gui_log("订单信息查询失败")
        return '亲亲~ 没有找到您的订单信息哦，请发送座位截图~'

    async def _handle_paid_message(self, parsed_msg):
        """处理已付款消息"""
        logger.debug(f"买家已付款: message_data")
        info = self.movie_api.movie_goofish_order_info(
            buyer_id=parsed_msg['user_id'],
            seller_id=self.myid,
            goods_id=parsed_msg['item_id'],
        )
        if info and info.get('code') == 200 and isinstance(info.get('data'), dict):
            # 更新订单状态为已付款待发货 (state=2)
            order_no = info['data'].get('order_no')
            if order_no:
                try:
                    update_result = self.movie_api.movie_goofish_order_update(order_no, 2)
                    add_gui_log(f"订单状态已更新为已付款待发货: {update_result}")
                except Exception as e:
                    logger.error(f"更新订单状态失败: {e}")
                    add_gui_log(f"更新订单状态失败: {e}")
            self._log_paid_order(info['data'])
            return '已收到您的付款，订单正在处理中，请稍等~'
        return '亲亲~ 请发送座位截图以便查询订单~'

    async def handle_message(self, websocket, message):
        """处理接收到的消息"""
        try:
            msg_data = json.loads(message)

            # 发送确认响应
            await self._send_ack(websocket, msg_data)

            # 提取消息数据
            if not self._is_valid_chat_message(msg_data):
                return

            data = msg_data["body"]["syncPushPackage"]["data"][0]["data"]

            # 尝试直接解析JSON（系统消息）
            if self._try_parse_json(data):
                return

            # 处理加密消息
            await self._process_encrypted_message(websocket, data)

        except Exception as e:
            logger.error(f"消息处理异常: {e}")

    async def _send_ack(self, websocket, msg_data):
        """发送确认响应"""
        ack_msg = {
            "code": 200,
            "headers": {
                "mid": msg_data["headers"].get("mid", generate_mid()),
                "sid": msg_data["headers"].get("sid", ''),
            }
        }
        for key in ['app-key', 'ua', 'dt']:
            if key in msg_data["headers"]:
                ack_msg["headers"][key] = msg_data["headers"][key]
        await websocket.send(json.dumps(ack_msg))

    def _is_valid_chat_message(self, msg_data):
        """检查是否为有效的聊天消息"""
        return ("body" in msg_data and
                "syncPushPackage" in msg_data["body"] and
                "data" in msg_data["body"]["syncPushPackage"] and
                msg_data["body"]["syncPushPackage"]["data"])

    def _try_parse_json(self, data):
        """尝试解析JSON消息（系统消息）"""
        if data.strip():
            try:
                json_data = json.loads(data)
                logger.debug(f"收到JSON消息: {json_data}")
                return True
            except json.JSONDecodeError:
                pass
        return False

    async def _process_encrypted_message(self, websocket, data):
        """处理加密消息"""
        try:
            decrypted_data = decrypt(data)
            if not decrypted_data:
                return

            message_data = json.loads(decrypted_data)
            parsed_msg = self._parse_message_content(message_data)

            if not parsed_msg:
                return

            # 忽略自己发送的消息
            if parsed_msg["user_id"] == self.myid:
                logger.info(f"[身份:自己]-[商品:{parsed_msg['item_id']}]-{parsed_msg['user_name']}: {parsed_msg['message']}")
                return

            # 处理消息并生成回复
            reply_data = await self._generate_reply(websocket, parsed_msg, message_data)

            # 发送回复
            if reply_data and "2" in message_data["1"]:
                cid = message_data["1"]["2"].split('@')[0]
                await self._send_reply(websocket, cid, parsed_msg["user_id"], reply_data)

        except Exception:
            # 静默处理解密失败和系统消息
            pass

    async def _generate_reply(self, websocket, parsed_msg, message_data):
        """根据消息类型生成回复"""
        msg_content = parsed_msg["message"]

        # 处理图片消息
        if msg_content["type"] == MSG_TYPE_IMAGE:
            return await self._handle_image_message(websocket, parsed_msg, parsed_msg["user_id"])

        # 处理文字消息
        logger.debug(f"解密后的消息数据: {message_data}")
        text_data = msg_content["data"]

        user_id = parsed_msg["user_id"]
        if user_id not in self._users_first_text_replied:
            self._users_first_text_replied.add(user_id)
            return {"type": "text_then_image", "text": self._get_purchase_notice(), "image_url": DEFAULT_ERROR_IMAGE}

        # 检测待付款消息
        if "我已拍下，待付款" in text_data or "买家已拍下，待付款" in text_data:
            reply = await self._handle_pending_payment_message(parsed_msg)
            return {'type': 'text', 'reply': reply}

        # 检测已付款消息
        elif "已付款" in text_data:
            reply = await self._handle_paid_message(parsed_msg)
            return {'type': 'text', 'reply': reply}

        # 其他消息
        else:
            logger.info(f"[消息类型:其他][身份:对方][用户:{parsed_msg['user_id']}]-[商品:{parsed_msg['item_id']}]-{parsed_msg['user_name']}: {msg_content}")
            return None

    async def _send_reply(self, websocket, cid, user_id, reply_data):
        """发送回复消息"""
        if reply_data['type'] == 'image_error':
            await self.send_msg(websocket, cid, user_id, reply_data['text_reply'])
            await asyncio.sleep(MESSAGE_DELAY)
            await self.send_image_msg(websocket, cid, user_id, reply_data['image_url'])
        elif reply_data['type'] == 'text_then_image':
            await self.send_msg(websocket, cid, user_id, reply_data['text'])
            await asyncio.sleep(2)
            await self.send_image_msg(websocket, cid, user_id, reply_data['image_url'])
        elif reply_data['type'] == 'text':
            await self.send_msg(websocket, cid, user_id, reply_data['reply'])

    async def main(self):
        """主循环 - 常驻进程用于接收消息和自动回复"""
        extra_headers = [
            ("Cookie", self.cookies_str),
            ("Host", "wss-goofish.dingtalk.com"),
            ("Connection", "Upgrade"),
            ("Pragma", "no-cache"),
            ("Cache-Control", "no-cache"),
            ("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"),
            ("Origin", "https://www.goofish.com"),
            ("Accept-Encoding", "gzip, deflate, br, zstd"),
            ("Accept-Language", "zh-CN,zh;q=0.9"),
        ]

        async with websockets.connect(self.base_url, extra_headers=extra_headers) as websocket:
            # 启动初始化任务和心跳任务
            await self.init_connection(websocket)
            asyncio.create_task(self.heart_beat(websocket))

            # 主消息循环
            async for message in websocket:
                await self.handle_message(websocket, message)

